﻿namespace Spectral
{
    using System;
    using System.Runtime.InteropServices;

    /// <summary>
    /// Represents a color.
    /// </summary>
    [StructLayout(LayoutKind.Explicit)]
    public partial struct Color : IEquatable<Color>
    {
        /// <summary>
        /// The alpha component.
        /// </summary>
        [FieldOffset(3)]
        public readonly byte A;

        /// <summary>
        /// The ref component.
        /// </summary>
        [FieldOffset(2)]
        public readonly byte R;

        /// <summary>
        /// The green component.
        /// </summary>
        [FieldOffset(1)]
        public readonly byte G;

        /// <summary>
        /// The blue component.
        /// </summary>
        [FieldOffset(0)]
        public readonly byte B;

        /// <summary>
        /// The packed value of the color.
        /// </summary>
        [FieldOffset(0)]
        public readonly int Value;

        /// <summary>
        /// Initializes a new instance of the <see cref="Color"/> struct.
        /// </summary>
        /// <param name="value">The packed value.</param>
        public Color(int value)
        {
            A = R = G = B = 0;
            Value = value;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Color"/> struct.
        /// </summary>
        /// <param name="r">The red component.</param>
        /// <param name="g">The green component.</param>
        /// <param name="b">The blue component.</param>
        public Color(byte r, byte g, byte b)
            : this(r, g, b, 255)
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Color"/> struct.
        /// </summary>
        /// <param name="r">The red component.</param>
        /// <param name="g">The green component.</param>
        /// <param name="b">The blue component.</param>
        /// <param name="a">The alpha component.</param>
        public Color(byte r, byte g, byte b, byte a)
        {
            Value = 0;

            R = r;
            G = g;
            B = b;
            A = a;
        }

        /// <summary>
        /// Inverts this color.
        /// </summary>
        /// <returns>A color with inverted values.</returns>
        public Color Invert()
        {
            return new Color((byte)(255 - R), (byte)(255 - G), (byte)(255 - B), (byte)(255 - A));
        }

        /// <summary>
        /// Indicates whether the current object is equal to another object of the same type.
        /// </summary>
        /// <param name="other">An object to compare with this object.</param>
        /// <returns>
        /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        public bool Equals(Color other)
        {
            return Value == other.Value;
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            return obj is Color ? Equals((Color)obj) : false;
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("R: {0}, G: {1}, B: {2}, A: {3}", R, G, B, A);
        }
    }
}
